package com.guigu.auth.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.guigu.auth.entity.AuthMenu;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.guigu.auth.entity.AuthRoleAuthority;
import com.guigu.auth.entity.AuthUser;
import com.guigu.auth.entity.AuthUserRole;
import com.guigu.auth.entity.dto.AuthMenuDTO;
import com.guigu.auth.entity.vo.AuthMenuRouterVO;
import com.guigu.auth.entity.vo.AuthMenuVO;
import com.guigu.auth.mapper.AuthMenuMapper;
import com.guigu.auth.service.*;
import com.guigu.commons.utils.JwtUtils;
import com.guigu.tms.exception.TmsException;
import com.guigu.tms.result.R;
import com.guigu.tms.result.ResultCode;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.NotNull;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * 菜单 服务实现类
 * </p>
 *
 * @author TaoLong
 * @since 2021-12-06
 */
@Service
@Slf4j
@CacheConfig(cacheNames = "authMenu")
public class AuthMenuServiceImpl extends ServiceImpl<AuthMenuMapper, AuthMenu> implements AuthMenuService {
    @Autowired
    private AuthRoleAuthorityService roleAuthorityService;

    @Autowired
    private AuthResourceService resourceService;

    @Autowired
    private AuthUserRoleService userRoleService;

    @Autowired
    private AuthUserService authUserService;

    @Autowired
    private AuthRoleAuthorityService authRoleAuthorityService;


    @Override
    public R<Set<AuthMenu>> queryMenuBy(String stationId) {

        Set<AuthMenu> set = new HashSet<>();
        if (StringUtils.isBlank(stationId)) {
            throw new TmsException(ResultCode.ERROR_CODE, "获取权限信息失败!");
        }
        /**
         * 根据岗位Id查询出角色信息
         */
        List<AuthUserRole> authUserRoles = getAuthUserRoles(stationId);

        authUserRoles.stream().forEach(authUserRole -> {
            R<List<AuthMenu>> r = queryMenuBaseOnRoleId2(String.valueOf(authUserRole.getRoleId()));
            if (CollUtil.isNotEmpty(r.getData())) {
                set.addAll(r.getData());
            }
        });

        return new R<>(ResultCode.SUCCESS_CODE, set);
    }

    @Override
    public R<List<AuthMenuVO>> queryAllMenu() {
        List<AuthMenu> authMenus = this.baseMapper.selectList(null);
        return new R<>(ResultCode.SUCCESS_CODE, queryAllMenu(authMenus));
    }

    @Override
    @Cacheable(key = "#request.getHeader('token')")
    public R<List<AuthMenuRouterVO>> queryAllMenuRouter(HttpServletRequest request) {
        String token = request.getHeader("token");
        /**
         * 获取用户Id
         */
        String id = JwtUtils.getMemberIdByJwtToken(token);
        /**
         * 根据用户Id查询对应的岗位信息
         */
        AuthUser user = authUserService.getById(id);
        if (ObjectUtils.isEmpty(user)) {
            throw new TmsException(ResultCode.ERROR_CODE, "令牌已失效或用户根本不存在");
        }
        R<Set<AuthMenu>> r = queryMenuBy(String.valueOf(user.getStationId()));
        if (CollUtil.isEmpty(r.getData())) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }
        List<AuthMenu> list = r.getData().stream().map(a -> {
            AuthMenu authMenu = new AuthMenu();
            BeanUtils.copyProperties(a, authMenu);
            return authMenu;
        }).collect(Collectors.toList());
        return new R<>(ResultCode.SUCCESS_CODE, queryAllMenuRouter(list));
    }

    @Override
    public R addAuthMenu(AuthMenuDTO authMenuDTO) {
        if (ObjectUtils.isEmpty(authMenuDTO)) {
            throw new TmsException(ResultCode.ERROR_CODE, "对象为null");
        }
        if (MapUtil.isEmpty(authMenuDTO.getMeta())) {
            throw new TmsException(ResultCode.ERROR_CODE, "元数据不能为空!");
        }
        try {
            AuthMenu authMenu = new AuthMenu();
            BeanUtils.copyProperties(authMenuDTO, authMenu);
            ObjectMapper objectMapper = new ObjectMapper();
            String meta = objectMapper.writeValueAsString(authMenuDTO.getMeta());
            authMenu.setMeta(meta);
            this.saveOrUpdate(authMenu);
        } catch (JsonProcessingException e) {
            e.printStackTrace();
            throw new TmsException(ResultCode.ERROR_CODE, "解析对象出错!");
        }
        return new R(ResultCode.SUCCESS_CODE, "添加菜单成功!", true);
    }

    @Override
    public R<Set<Long>> queryMenuBasedOnStationId(String stationId) {
        Set<Long> set = new HashSet<>();
        if (StringUtils.isBlank(stationId)) {
            throw new TmsException(ResultCode.ERROR_CODE, "用户编号不能为空!");
        }
        AuthUser user = authUserService.getById(Long.valueOf(stationId));
        /**
         * 根据岗位id查询出对应的角色信息
         */
        if (ObjectUtils.isEmpty(user)) {
            throw new TmsException(ResultCode.ERROR_CODE, "用户信息为空!");
        }

        QueryWrapper<AuthUserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id", user.getStationId());
        List<AuthUserRole> roleList = userRoleService.list(userRoleQueryWrapper);
        if (CollUtil.isEmpty(roleList)) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }

        roleList.stream().map(authUserRole -> {
            R<List<Long>> r = queryMenuBaseOnRoleId(String.valueOf(authUserRole.getRoleId()));
            return r.getData();
        }).forEach(authMenuRouterVOS -> {
            if (CollUtil.isNotEmpty(authMenuRouterVOS)) {
                set.addAll(authMenuRouterVOS);

            }
        });
        return new R<>(ResultCode.SUCCESS_CODE, set);
    }

    @Override
    public R<List<Long>> queryMenuBaseOnRoleId(String roleId) {
        if (StringUtils.isBlank(roleId)) {
            throw new TmsException(ResultCode.ERROR_CODE, "角色id为空!");
        }
        /**
         * 根据角色id查询出对应的菜单Id集合
         */
        QueryWrapper<AuthRoleAuthority> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("authority_id");
        queryWrapper.eq("role_id", roleId);
        List<AuthRoleAuthority> authorityList = authRoleAuthorityService.list(queryWrapper);
        List<Long> menusId = authorityList.stream().map(s -> s.getAuthorityId()).collect(Collectors.toList());
        if (CollUtil.isEmpty(menusId)) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }
        /**
         * 在根据菜单集合查询对应的菜单
         */
        List<AuthMenu> list = (List<AuthMenu>) this.listByIds(menusId);
        if (CollUtil.isEmpty(list)) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }


        /**
         * 将类型转换为VO视图对象
         */
        List<Long> longList = list.stream().filter(s -> s.getParentId() != 0).map(s -> s.getId()).collect(Collectors.toList());
        return new R<>(ResultCode.SUCCESS_CODE, longList);
    }


    public R<List<AuthMenu>> queryMenuBaseOnRoleId2(String roleId) {
        if (StringUtils.isBlank(roleId)) {
            throw new TmsException(ResultCode.ERROR_CODE, "角色id为空!");
        }
        /**
         * 根据角色id查询出对应的菜单Id集合
         */
        QueryWrapper<AuthRoleAuthority> queryWrapper = new QueryWrapper<>();
        queryWrapper.select("authority_id");
        queryWrapper.eq("role_id", roleId);
        List<AuthRoleAuthority> authorityList = authRoleAuthorityService.list(queryWrapper);
        List<Long> menusId = authorityList.stream().map(s -> s.getAuthorityId()).collect(Collectors.toList());
        if (CollUtil.isEmpty(menusId)) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }
        /**
         * 在根据菜单集合查询对应的菜单
         */
        List<AuthMenu> list = (List<AuthMenu>) this.listByIds(menusId);
        if (CollUtil.isEmpty(list)) {
            return new R<>(ResultCode.SUCCESS_CODE, null);
        }
        return new R<>(ResultCode.SUCCESS_CODE, list);
    }


    /**
     * 递归查询子菜单
     *
     * @param list
     * @return
     */
    private List<AuthMenuVO> queryAllMenu(List<AuthMenu> list) {
        List<AuthMenuVO> voList = new ArrayList<>();
        for (AuthMenu menu : list) {
            /**
             * 如果当前Id为0,那么代表它就是最上级,没有上级了
             */
            if (0 == menu.getParentId()) {
                voList.add(findChildren(menu, list));
            }
        }
        log.info("菜单数据为:{}", voList);
        return voList;
    }

    /**
     * 查询父Id以下的子菜单
     *
     * @param menu
     * @param list
     * @return
     */
    private AuthMenuVO findChildren(AuthMenu menu, List<AuthMenu> list) {

        AuthMenuVO authMenuVO = null;
        try {
            authMenuVO = new AuthMenuVO();
            BeanUtils.copyProperties(menu, authMenuVO);
            if (StringUtils.isNotBlank(menu.getMeta())) {
                ObjectMapper objectMapper = new ObjectMapper();
                Map map = objectMapper.readValue(menu.getMeta(), Map.class);
                authMenuVO.setMeta(map);
            }
            authMenuVO.setChildren(new ArrayList<AuthMenuVO>());
            for (AuthMenu authMenu : list) {
                /**
                 * 一直往下查询,直到没有为止
                 */
                if (menu.getId().longValue() == authMenu.getParentId().longValue()) {
                    authMenuVO.getChildren().add(findChildren(authMenu, list));
                }
            }
            return authMenuVO;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 递归查询子菜单
     *
     * @param list
     * @return
     */
    private List<AuthMenuRouterVO> queryAllMenuRouter(List<AuthMenu> list) {
        List<AuthMenuRouterVO> voList = new ArrayList<>();
        for (AuthMenu menu : list) {
            /**
             * 如果当前Id为0,那么代表它就是最上级,没有上级了
             */
            if (0 == menu.getParentId()) {
                voList.add(findChildrenRouter(menu, list));
            }
        }
        return voList;
    }

    /**
     * 查询父Id以下的子菜单
     *
     * @param menu
     * @param list
     * @return
     */
    private AuthMenuRouterVO findChildrenRouter(AuthMenu menu, List<AuthMenu> list) {

        AuthMenuRouterVO authMenuVO = null;
        try {
            authMenuVO = new AuthMenuRouterVO();
            BeanUtils.copyProperties(menu, authMenuVO);
            if (StringUtils.isNotBlank(menu.getMeta())) {
                ObjectMapper objectMapper = new ObjectMapper();
                Map map = objectMapper.readValue(menu.getMeta(), Map.class);
                authMenuVO.setMeta(map);
            }
            authMenuVO.setChildren(new ArrayList<AuthMenuRouterVO>());
            for (AuthMenu authMenu : list) {
                /**
                 * 一直往下查询,直到没有为止
                 */
                if (menu.getId().longValue() == authMenu.getParentId().longValue()) {
                    authMenuVO.getChildren().add(findChildrenRouter(authMenu, list));
                }
            }
            return authMenuVO;
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 获取角色对应的权限资源信息(使用set保证唯一)
     *
     * @param authUserRoles 角色数据集合
     * @return
     */
    @NotNull
    private Set<AuthRoleAuthority> getRoleAuthorities(List<AuthUserRole> authUserRoles) {
        Set<AuthRoleAuthority> authoritySet = new HashSet<>();
        for (AuthUserRole role : authUserRoles) {
            if (null == role.getRoleId()) {
                throw new TmsException(ResultCode.ERROR_CODE, "获取权限失败!");
            }
            QueryWrapper<AuthRoleAuthority> roleAuthorityQueryWrapper = new QueryWrapper<>();
            roleAuthorityQueryWrapper.eq("role_id", role.getRoleId());
            /**
             * 获取角色的资源信息
             */
            List<AuthRoleAuthority> roleAuthorities = roleAuthorityService.list(roleAuthorityQueryWrapper);
            if (CollUtil.isNotEmpty(roleAuthorities)) {
                /**
                 * 如果查询出信息资源信息不为空,那么加入到这个set中
                 */
                authoritySet.addAll(roleAuthorities);
            }
        }
        return authoritySet;
    }

    /**
     * 获取 用户和角色之间的关联关系(用户Id指的是岗位Id)
     *
     * @param stationId 岗位
     * @return
     */
    private List<AuthUserRole> getAuthUserRoles(String stationId) {
        QueryWrapper<AuthUserRole> userRoleQueryWrapper = new QueryWrapper<>();
        userRoleQueryWrapper.eq("user_id", stationId);
        List<AuthUserRole> authUserRoles = userRoleService.list(userRoleQueryWrapper);
        return authUserRoles;
    }
}
